<?php
/**
 * Author: zhao-baolin
 * E-mail: qiutian@fengyumeng.com
 */

namespace System;



class Model
{
    static $instance;

    const FETCH_OBJ = \PDO::FETCH_OBJ;
    const FETCH_CLASS = \PDO::FETCH_CLASS;

    protected $type = 'mysql'; //数据库类型
    protected $hostname = '';   //数据库地址
    protected $database = '';   //数据库名
    protected $username = '';   //登录名
    protected $password = '';   //密码
    protected $charset = 'utf8';//字符集
    protected $name = '';       //表名

    protected $connect = '';    //连接实例
    protected $statement = '';  //PDOStatement对象
    protected $sql_type = '';   //sql类型
    protected $sql = '';        //sql语句
    protected $field = ' * ';   //字段
    protected $limit = ' ';     //页数
    protected $where = ' ';     //条件
    protected $alias = ' ';     //别名
    protected $order = ' ';     //排序
    protected $group = ' ';     //分组
    protected $having = ' ';    //条件
    protected $join = ' ';      //Join
    protected $distinct = ' ';  //去重
    protected $data = ' ';      //增改键值串



    private function __construct()
    {
        $config = include_once COMMON_PATH.'Database.php';

        foreach($config as $k => $v){
            if(isset($this->$k) && $v){
                $this->$k = $v;
            }
        }
        $this->connect();
    }

    //单例
    static function instance($name)
    {
        if(!self::$instance instanceof Model){
            self::$instance = new self();
        }

        return self::$instance->name($name);
    }


    //连接
    public function connect()
    {
        $this->connect = new \PDO('mysql:host='.$this->hostname.';dbname='.$this->database,$this->username, $this->password);
        $this->connect->query('set names '.$this->charset);
    }


    //设置表名
    public function name($table = '')
    {
        if($table){
            $this->name = $table;
        }
        return self::$instance;
    }


    //执行一条sql语句 通吃
    public function query($sql)
    {
        $this->filter($sql);

        $this->sql_type = strtoupper(substr($this->sql,0,6));
        $result = null;

        $this->statement = $this->connect->prepare($this->sql);
        $this->statement->execute();

        switch ($this->sql_type){
            case 'SELECT':
                $result = $this->statement->fetchAll(self::FETCH_CLASS);
                break;
            case 'DELETE':
            case 'UPDATE':
                $result = $this->statement->rowCount();
            break;
            default:
                break;
        }
        $this->clean();
        return $result;
    }


    //条件
    public function where($whe = '')
    {
        $w = '';
        $is_logic = '';
        if(is_array($whe) && $c = count($whe)){
            if(isset($whe['_logic']) && !empty($whe['_logic'])){
                $is_logic = $whe['_logic'];
                unset($whe['_logic']);
                $c --;
            }
            foreach($whe as $k => $v){
                if(is_array($v)){
                    $cc = count($v);
                    switch ($cc){
                        case 1:
                            $w .= $k.' = "'.addslashes($v[0]).'" ';
                            break;
                        case 2:
                            if(is_array($v[0]) && is_array($v[1])){
                                list($a1,$a2) = $v[0];
                                list($b1,$b2) = $v[1];
                                $w .= '( '.$k.' '.$a1.' '.addslashes($a2).' ) AND ( '.$k.' '.$b1.' '.addslashes($b2).' )';
                            }elseif(preg_match('/^(notbetween|not between|between)$/',$v[0])){
                                $a = $v[1];
                                if(is_string($v[1])){
                                    $a = explode(',',$v[1]);
                                }
                                $w .= $k.' '.$v[0];
                                foreach($a as $ak => $av){
                                    if($ak){
                                        $w .= ' AND "'.addslashes($av).'" ';
                                    }else{
                                        $w .= ' "'.addslashes($av).'" ';
                                    }
                                }
                            }elseif(preg_match('/^(notin|not in|in)$/',$v[0])){
                                $a = $v[1];
                                if(is_string($v[1])){
                                    $a = explode(',',$v[1]);
                                }
                                $w .= $k.' '.$v[0].'(';
                                foreach($a as $ak => $av){
                                    if($ak){
                                        $w .= ' , "'.addslashes($av).'" ';
                                    }else{
                                        $w .= ' "'.addslashes($av).'" ';
                                    }
                                }
                                $w .= ') ';
                            }else{
                                $w .= $k.' '.$v[0].' "'.addslashes($v[1]).'" ';
                            }
                            break;
                        case 3:
                            if(is_array($v[0]) && is_array($v[1]) && is_string($v[2])){
                                list($a1,$a2) = $v[0];
                                list($b1,$b2) = $v[1];
                                $w .= '( '.$k.' '.$a1.' '.addslashes($a2).' ) '.$v[2].' ( '.$k.' '.$b1.' '.addslashes($b2).' )';
                            }
                            break;
                        default:
                            break;
                    }

                }else{
                    $w .= $k.' = "'.addslashes($v).'" ';
                }
                $c --;
                if($c){
                    $w .= $is_logic ? ' '.$is_logic.' ' : ' AND ';
                }
            }
            $this->where = $w;
        }elseif(is_string($whe)){
            $w = $whe;
        }
        $this->where = $w;
        return self::$instance;
    }

    //查询
    public function select()
    {
        $this->sql_type = 'SELECT';
        $this->execute();
        return $this->statement->fetchAll(self::FETCH_CLASS);
    }

    //查询单条数据
    public function find()
    {
        $this->sql_type = 'SELECT';
        $this->execute();
        return $this->statement->fetch(self::FETCH_OBJ);
    }

    //查询条数
    public function count($as = '')
    {
        $this->sql_type = 'SELECT';
        $this->field = ' COUNT(*) '.$as;
        $this->execute();
        return $this->statement->fetch(self::FETCH_OBJ);
    }

    //添加
    public function add($d = [])
    {
        return $this->insert($d);
    }

    //添加
    public function insert($d = [])
    {
        $this->sql_type = 'INSERT INTO';
        if($d && is_array($d)){
            $this->data($d);
        }
        $this->sql = $this->sql_type.' '.$this->name.' '.$this->data;
        $this->statement = $this->connect->prepare($this->sql);
        $this->statement->execute();
        $this->clean();
        return $this->connect->lastInsertId();
    }

    //批量添加
    public function addAll($all = [])
    {
        return $this->addAll($all);
    }

    //批量添加
    public function insertAll($all = [])
    {
        $this->sql_type = 'INSERT INTO';
        $keys = '('.implode(',',array_values($all[0])).')';
        $count = count($all);
        $values = ' VALUES ';
        for($i=1;$i<$count;$i++){
            $i == 1 or $values .= ',';

            foreach($all[$i] as $k => &$v){
                $v = '"'.addslashes($v).'"';
            }
            $values .= '('.implode(',',array_values($all[$i])).')';
        }
        $this->sql = $this->sql_type.' '.$this->name.' '.$keys.' '.$values;
        $this->statement = $this->connect->prepare($this->sql);
        $this->statement->execute();
        $this->clean();
        return $this->statement->rowCount();
    }

    //修改
    public function save($data)
    {
        $this->sql_type = 'UPDATE';
        $s = ' SET ';
        $i = 0;
        foreach($data as $k => $v){
            $i && $s .= ',';
            $s .= $k.'="'.addslashes($v).'"';
            $i ++ ;
        }
        $this->parseWhere();
        $this->sql = $this->sql_type.' '.$this->name.$s.$this->where;
        $this->statement = $this->connect->prepare($this->sql);
        $this->statement->execute();
        $this->clean();
        return $this->statement->rowCount();
    }

    //删除
    public function delete()
    {
        $this->sql_type = 'DELETE';
        $this->field = '';
        $this->execute();
        return $this->statement->rowCount();
    }

    //数据存储
    public function data($d)
    {
        if(is_array($d)){
            $key = array_keys($d);
            $key = '('.implode(',',$key).')';
            //p($key);
            $val = array_values($d);
            foreach($val as $k => &$v){
                $v = '"'.addslashes($v).'"';
            }
            $val = '('.implode(',',$val).')';
            $this->data = $key.' VALUES '.$val;
        }

        return self::$instance;
    }

    //联查
    public function join($j)
    {
        if(is_string($j)){
            if(false !== stripos($j,'JOIN')){
                $this->join .= $j;
            }else{
                $this->join .= ' INNER JOIN '.$j;
            }
        }
        return self::$instance;
    }

    //指定条数
    public function limit(int $limit_start = 0,int $limit_end = 0)
    {
        if($limit_start && !$limit_end){
            $this->limit = ' limit '.$limit_start;
        }elseif (!$limit_start && $limit_end){
            $this->limit = ' limit 0,'.$limit_end;
        }elseif ($limit_start && $limit_end){
            $this->limit = ' limit '.$limit_start.','.$limit_end;
        }else{
            $this->limit = '';
        }
        return self::$instance;
    }

    //分页
    public function page($page = 1,$list_rows = 10)
    {
        if(is_numeric($page) && $page > 0){
            $page = ($page - 1) * $list_rows;
        }
        $this->limit($page,$list_rows);
        return self::$instance;
    }

    //分组
    public function group($g)
    {
        if(is_string($g) && $g){
            $this->group = ' GROUP BY '.$g;
        }
        return self::$instance;
    }

    //别名
    public function alias($asName = '')
    {
        $this->alias .= $asName.' ';
        return self::$instance;
    }

    //指定字段
    public function field($f)
    {
        $this->field = ' ';
        if(is_array($f)){
            $c = count($f);
            foreach($f as $k => $v){
                $c--;
                if(is_array($v)){
                    foreach($v as $a => $b){
                        $this->field .= $a.' as '.$b;
                    }
                }else{
                    if(is_numeric($k)){
                        $this->field .= $v;
                    }else{
                        $this->field .= $k.' as '.$v;
                    }
                }
                if($c){
                    $this->field .= ',';
                }
            }
        }else{
            $this->field .= $f;
        }

        return self::$instance;

    }

    //排序
    public function order($o)
    {
        if($o){
            $this->order .= ' ORDER BY ';
        }
        if(is_array($o)){
            $c = count($o);
            foreach($o as $k => $v){
                $c --;
                if(is_numeric($k)){
                    $this->order .= $v;
                }else{
                    $this->order .= $k.' '.$v;
                }
                if($c){
                    $this->order .= ',';
                }
            }
        }else{
            $this->order .= $o;
        }
        return self::$instance;
    }

    //having条件
    public function having($h)
    {
        if(is_string($h) && $h){
            $this->having .= ' HAVING '.$h;
        }
        return self::$instance;
    }

    //去重
    public function distinct(bool $d)
    {
        if(true == $d){
            $this->distinct = ' DISTINCT ';
        }
        return self::$instance;
    }

    //组装sql
    private function splice()
    {
        $this->parseWhere();
        $this->sql =
            $this->sql_type.
            $this->distinct.
            $this->field.
            ' from '.$this->name.
            $this->alias.
            $this->join.
            $this->where.
            $this->group.
            $this->having.
            $this->order.
            $this->limit;
    }


    //执行
    private function execute()
    {
        $this->splice();
        $this->statement = $this->connect->prepare($this->sql);
        $this->statement->execute();
        $this->clean();
    }

    //分析条件
    private function parseWhere()
    {
        $this->where = $this->where ? ' where '.$this->where :'';
    }


    //sql过滤
    private function filter($sql){
        $this->sql = str_replace(['#','/*','*/','--'],'',trim($sql));
    }


    //获取最后一次执行的sql语句
    public function _sql()
    {
        return $this->sql;
    }

    //清理条件 避免污染下次查询
    private function clean()
    {
        $this->name = '';
        $this->sql_type = '';
        $this->field = ' * ';
        $this->where = '';
        $this->limit = ' ';
        $this->alias = ' ';
        $this->order = ' ';
        $this->having = ' ';
        $this->join = ' ';
        $this->distinct = ' ';
        $this->data = ' ';
    }

    //禁止克隆
    private function __clone()
    {
        // TODO: Implement __clone() method.
    }

}